package com.gopay.common.logging;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import org.quartz.CronExpression;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

import com.alibaba.fastjson.JSONObject;
import com.gopay.common.util.LoadBalancingUtils;

public class RedisAppender extends AppenderSkeleton {
	
	private boolean initialized = false;
	private boolean storeSwitch = true;
	private int maxAllowedErrorCount = 0;

	/**
	 * 应用域，比如：cps, acps
	 */
	private String domain;
	
	private String host;
	private int port;
	private String ip;
	private String channel = "logsprod";
	
	private int jedisPoolMaxTotal = 5;
	private int jedisPoolMaxIdle = 2;
	private int jedisPoolMinIdle = 2;
	private int jedisPooMaxWaitMillis = 30000;
	
	private Scheduler scheduler;
	private static volatile boolean jobStarting = false;
	
	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}
	
	public boolean isStoreSwitch() {
		return storeSwitch;
	}

	public void setStoreSwitch(boolean storeSwitch) {
		this.storeSwitch = storeSwitch;
	}

	public int getMaxAllowedErrorCount() {
		return maxAllowedErrorCount;
	}

	public void setMaxAllowedErrorCount(int maxAllowedErrorCount) {
		this.maxAllowedErrorCount = maxAllowedErrorCount;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getChannel() {
		return channel;
	}

	public void setChannel(String channel) {
		this.channel = channel;
	}

	public int getJedisPoolMaxTotal() {
		return jedisPoolMaxTotal;
	}

	public void setJedisPoolMaxTotal(int jedisPoolMaxTotal) {
		this.jedisPoolMaxTotal = jedisPoolMaxTotal;
	}

	public int getJedisPoolMaxIdle() {
		return jedisPoolMaxIdle;
	}

	public void setJedisPoolMaxIdle(int jedisPoolMaxIdle) {
		this.jedisPoolMaxIdle = jedisPoolMaxIdle;
	}

	public int getJedisPoolMinIdle() {
		return jedisPoolMinIdle;
	}

	public void setJedisPoolMinIdle(int jedisPoolMinIdle) {
		this.jedisPoolMinIdle = jedisPoolMinIdle;
	}

	public int getJedisPooMaxWaitMillis() {
		return jedisPooMaxWaitMillis;
	}

	public void setJedisPooMaxWaitMillis(int jedisPooMaxWaitMillis) {
		this.jedisPooMaxWaitMillis = jedisPooMaxWaitMillis;
	}

	@Override
	public boolean requiresLayout() {
		return false;
	}

	@Override
	public void activateOptions() {
		try {
			if(storeSwitch && !jobStarting){
				SchedulerFactory factory = new StdSchedulerFactory();
				scheduler = factory.getScheduler();

				JobDetail jobDetail = new JobDetail();
				jobDetail.setJobClass(LogsConsumeJob.class);
				jobDetail.setName("jobDetail");
				jobDetail.setGroup("jobDetailGroup");
				
				jobDetail.getJobDataMap().put("host", host);
				jobDetail.getJobDataMap().put("port", port);
				
				jobDetail.getJobDataMap().put("channel", channel);
				
				jobDetail.getJobDataMap().put("maxAllowedErrorCount", maxAllowedErrorCount);
				
				jobDetail.getJobDataMap().put("jedisPoolMaxTotal", jedisPoolMaxTotal);
				jobDetail.getJobDataMap().put("jedisPoolMaxIdle", jedisPoolMaxIdle);
				jobDetail.getJobDataMap().put("jedisPoolMinIdle", jedisPoolMinIdle);
				jobDetail.getJobDataMap().put("jedisPooMaxWaitMillis", jedisPooMaxWaitMillis);

				CronTrigger cronTrigger = new CronTrigger("cronTrigger", "triggerGroup");
				CronExpression ce = new CronExpression("*/3 * * * * ?");
				cronTrigger.setCronExpression(ce);

				scheduler.scheduleJob(jobDetail, cronTrigger);
				scheduler.start();
				
				jobStarting = true;
			}
			
			ip = LoadBalancingUtils.getRealIp();
			
			this.initialized = true;
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	@Override
	public void close() {
		if (this.scheduler != null) {
			try {
				this.scheduler.shutdown();
			} catch (SchedulerException e) {
				e.printStackTrace();
			}
		}
	}

	public boolean isInitialized() {
		return this.initialized;
	}

	@Override
	protected void append(LoggingEvent event) {
		
		if (!storeSwitch) {
            return;
        }
		
		if (this.initialized && event != null) {
			try{
				StringBuilder sb = new StringBuilder();
				sb.append(this.layout.format(event));
				if (this.layout.ignoresThrowable()) {
					String[] s = event.getThrowableStrRep();
					if (s != null) {
						int len = s.length;
						for (int i = 0; i < len; i++) {
							sb.append(s[i]).append(Layout.LINE_SEP);
						}
					}
				}
				
				JSONObject jo = new JSONObject();
				jo.put("d", domain);
				jo.put("t", event.getTimeStamp());
				jo.put("i", ip);
				jo.put("m", sb.toString());
				
				String joStr = JSONObject.toJSONString(jo);
				LogsCollector.getInstance().collect(joStr);
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
}